﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Collections.Specialized.BitVector32;

namespace ConsoleApp1
{
    //观察者模式：可以针对被观察对象与观察对象之间一对多的依赖关系监理起一种行为自动触发机制，当被观察对象状态发生变化时主动对外发起广播，以通知所有观察者做出响应。
   
    //现实中观察者往往是主动方，这是由于目标主题缺乏主观能动性造成的，其状态的更新并不能主动地通知观察者，这就造成观察行为的持续往复，
    //而在软件设计中我们可以将目标主题作为主动角色，将观察者反转为被动方角色，建立反向驱动式的消息响应机制，以此来避免做无用功，优化软件效率。

    //适用于具有一对多对象结构的场景，它支持多个观察者订阅一个目标主题，一旦目标主题的状态发生变化，目标对象便主动进行广播，即刻对所有订阅者发布全员消息通知。

    //原理与优点概述：
    //基于一对多的关系网，观察者模式以多态化的方式弱化目标主题与观察者之间的强耦合的依赖关系，标准化他们的消息交互接口，并让主客关系发生反转，
    //以"单方驱动全局模式"取代"多方持续轮询模式"，使目标主题的任何状态更新都能被即刻通过广播通知到观察者，解决了状态同步知悉的效率问题。
    internal class Program
    {
        static void Main(string[] args)
        {
            Shop shop = new Shop();
            Buyer buyer1 = new PhoneFans("老王");
            Buyer buyer2 = new HandChopper("老张");
            shop.RegisterBuyer(buyer1);
            shop.RegisterBuyer(buyer2);
            shop.SetProduct("苹果手机");
            shop.SetProduct("猪肉炖粉条");

            Console.WriteLine("-----------------------------------分割线------------------------------------");


            Publisher<string> publisher = new ShopPlus("商店");
            Buyer buyer3 = new PhoneFans("小美");
            Buyer buyer4 = new HandChopper("小红");
            //订阅事件
            Action<string> action1 = new Action<string>(s => 
            {
            if(s.Contains("手机"))
                {
                    buyer3.Inform(s);
                }
            
            });

            Action<string> action2 = new Action<string>(s =>
            {
                buyer4.Inform(s);
            });            
            publisher.RegisterAction(action1);
            publisher.RegisterAction(action2);
            //发布
            publisher.Publish("苹果手机");
            publisher.Publish("猪肉炖粉条");

            Console.ReadKey();
        }
    }


    #region 观察者模式在购买者和商店系统中的应用
    #region 发布者
   public class Shop
    {
        string Product { set; get; }
        /// <summary>
        /// 订阅者列表
        /// </summary>
        List<Buyer> Buyers = new List<Buyer>();

        public void RegisterBuyer(Buyer buyer)
        {
            this.Buyers.Add(buyer);
        }

        public string GetProduct()
        {
            return this.Product;
        }

        public void SetProduct(string product)
        {
            this.Product = product;
            this.NotifyBuyers();
        }

        /// <summary>
        /// 通知订阅者
        /// </summary>
        private void NotifyBuyers()
        {
            foreach (var item in Buyers)
            {
                item.Inform(this.Product);
            }
        }
    }
    #endregion

    #region 订阅者
    public abstract class Buyer
    {
        protected string Name { set; get; }
        public Buyer(string name)
        {
            this.Name = name;
        }

        public abstract void Inform(string product);

    }

    public class PhoneFans : Buyer
    {
        public PhoneFans(string name) : base(name)
        {
        }

        public override void Inform(string product)
        {
           if(product.Contains("手机"))
            {
                Console.WriteLine(this.Name + "购买了"+product);
            }
        }
    }

    public class HandChopper : Buyer
    {
     public HandChopper(string name):base(name)
        {

        }

        public override void Inform(string product)
        {
            Console.WriteLine(this.Name+"购买了"+product);
        }
    }


    #endregion
    #endregion


    #region 订阅与发布
    #region 订阅与发布
    public class Publisher<T>
    {
        private string Name;
        public Publisher(string name)
        {
            Name = name;
        }

        /// <summary>
        /// 订阅事件
        /// </summary>
        List<Action<T>> SubscribedActions = new List<Action<T>>();
        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public Action<T> RegisterAction(Action<T> action)
        {
            if (!this.SubscribedActions.Contains(action))
            {         
                this.SubscribedActions.Add (action);
            }
            return action;  
        }

        /// <summary>
        /// 发布
        /// </summary>
        public void Publish(T value)
        {
            foreach (var item in SubscribedActions)
            {
                item.BeginInvoke(value, null, null);
            }
        }
    }

    public class ShopPlus : Publisher<string>
    {
        public ShopPlus(string name) : base(name)
        {
        }
    }

    #endregion

    #endregion
}
